using System;
using System.IO;
using XTCast.Mp3;
using XTCast.Mp3.Encode;
using XTCast.Mp3.Decode;
using TerastarLib.Utils;

namespace XTCast.Mp3
{
	/// <summary>
	/// Summary description for MP3EncodeLive.
	/// </summary>
	
	public class MP3EncodeLive:IFrameReader,IDisposable 
	{
		private MP3Frame frame=new MP3Frame();
		private bool readFrame = false;
		private XTCast.Wave.WaveInRecorder m_Recorder;
		private Stream encode;
		private FifoStream fifo;
		private int bitrate, sampleRate, channels;
		private XTCast.Wave.WaveFormat wf;
		private byte[] m_RecBuffer;
		private bool closed;

		public MP3EncodeLive(int bitrate, int channels, int sampleRate):base() 
		{
			this.fifo = new FifoStream();
			this.bitrate = bitrate;
			this.channels = channels;
			this.sampleRate = sampleRate;
			this.wf = new XTCast.Wave.WaveFormat(sampleRate,16,channels); 
		}

		public void Start() 
		{
			m_Recorder = new XTCast.Wave.WaveInRecorder(0, wf, 32768, 3, new XTCast.Wave.BufferDoneEventHandler(DataArrived));
		}

		public void DataArrived(IntPtr data,int size) 
		{
			if (closed) return;
			if(m_RecBuffer == null || m_RecBuffer.Length < size) m_RecBuffer = new byte[size];
			System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 0, size);
			if (encode == null) 
			{
				BE_CONFIG be = new BE_CONFIG(wf,bitrate/1000,sampleRate);	
				if (closed) return;
				encode = new EncodeFilter(fifo,wf,be);
				//encode = new PCM.PCMRemoveSilence(encode,wf);
			}
			encode.Write(m_RecBuffer, 0, size);
		}

		private bool ReadFrame() 
		{
			while (!readFrame) 
			{
				if (frame.ReadFrame(fifo))
					readFrame = !frame.IsVbrFrame;
				else 
					return false;
			}
			return true;
		}

		public virtual byte[] ReadFrames(FrameReadInfo info) 
		{
			byte[] b = new byte[info.RequestLength];
			info.ActualLength=0;
			info.ActualFrames=0;
			info.EOF=false;

			while (info.ActualMillis < info.RequestMillis) 
			{
				if (!ReadFrame()) 
				{
					info.EOF = true;
					return b;
				}
				if (info.ActualLength+frame.Size > info.RequestLength )
					return b;
				readFrame = false;
				Array.Copy(frame.Frame, 0, b, info.ActualLength, frame.Size);
				info.ActualLength += frame.Size; info.ActualFrames++;
			}
			return b;
		}

		public virtual void SkipFrames(FrameReadInfo info) 
		{
			info.ActualLength=0;
			info.ActualFrames=0;
			info.EOF=false;
		}

		public void Dispose() 
		{
			Close();
			GC.SuppressFinalize(this);
		}

		public void Close() 
		{
			closed=true;
			if (fifo!=null) 
			{
				fifo.Close();
				fifo=null;
			}
			if (encode!=null) 
			{
				encode.Close();
				encode=null;
			}
			if (m_Recorder!=null) 
			{
				m_Recorder.Dispose();
				m_Recorder=null;
			}
		}
	
		public int Channels 
		{
			get 
			{
				return channels;
			}
		}
	
		public int SampleRate 
		{
			get 
			{
				return sampleRate;
			}
		}

		public int AvgBitrate 
		{
			get 
			{
				return bitrate;
			}
		}

		public void Reset() 
		{
			
		}
		public long Length
		{
			get 
			{
				return fifo.Length;
			}
		}
	}
}